package org.flexthinker.module.impl
{
    import mx.events.ModuleEvent;

    import org.flexthinker.module.Descriptor;
    import org.flexthinker.module.DescriptorLoader;
    import org.flexthinker.module.DescriptorLoaderFactory;

    import flash.events.Event;

    import flash.system.ApplicationDomain;

    import flash.system.SecurityDomain;

    import flash.utils.ByteArray;

    import mx.core.IFlexModuleFactory;
    import mx.core.UIComponent;

    import mx.logging.ILogger;
    import mx.logging.Log;
    import mx.utils.StringUtil;

    /**
     * Loads multiple moduleDescriptors at once.
     */
    public class CompositeModuleDescriptorLoader extends CompositeDescriptorLoader
    {
        private var log:ILogger = Log.getLogger("org.flexthinker.module.impl.CompositeModuleDescriptorLoader");
        private var compositeModuleDescriptor:CompositeModuleDescriptor;

        private var numModuleLoadersCompleted:int = 0;

        public function CompositeModuleDescriptorLoader(descriptor:Descriptor,
                loaderFactory:DescriptorLoaderFactory = null)
        {
            super(descriptor, loaderFactory);
            initDescriptor();
        }


        /**
         * Call this method after <code>ModuleEvent.READY</code> event,
         * in order to add the descriptors(skins, modules )
         * into the <code>targetObject</code> component.
         * @param targetObject
         *          The Visual Component where the module should be added
         */
        override public function init(targetObject:UIComponent):void
        {
            //super.init(targetObject);
            numModuleLoadersCompleted = 0;
            initDependencies(targetObject);
        }


        override public function load(applicationDomain:ApplicationDomain = null, securityDomain:SecurityDomain = null,
                bytes:ByteArray = null, moduleFactory:IFlexModuleFactory = null):void
        {
            super.load(applicationDomain, securityDomain, bytes, moduleFactory);
        }

        // -------------
        //   internals
        // --------------

        override protected function getDescriptors():Vector.<Descriptor>
        {
            return compositeModuleDescriptor.children;
        }


        override protected function moduleReady(event:ModuleEvent):void
        {
            super.moduleReady(event);
        }

        /**
         * When this method is called, the module and its dependencies are all ready,
         * and they have been also added to the UI.
         */
        protected function complete():void
        {
            dispatchEvent(new Event(Event.COMPLETE));
        }

        private function initDescriptor():void
        {
            compositeModuleDescriptor = CompositeModuleDescriptor(descriptor);
        }


        private function initDependencies(targetModule:UIComponent):void
        {
            for each (var loader:DescriptorLoader in getDescriptorLoaders())
            {
                CONFIG::DEBUG
                {
                    log.debug("{0}.init({1}) ( ready={2} ) ... in  {3} ", loader, targetModule, loader.ready, this);
                }
                loader.addEventListener(Event.COMPLETE, loader_completeHandler);
                loader.init(targetModule);
            }
        }

        private function loader_completeHandler(event:Event):void
        {
            var loader:DescriptorLoader = DescriptorLoader(event.currentTarget);
            loader.removeEventListener(Event.COMPLETE, loader_completeHandler);

            numModuleLoadersCompleted++;
            CONFIG::DEBUG
            {
                log.debug(StringUtil.substitute("{0} Descriptor has completed initialization from url {1}", loader,
                        loader.url));
                log.debug(StringUtil.substitute("{0} out of {1} descriptors Completed", numModuleLoadersCompleted,
                        numDescriptors));
            }
            if (numModuleLoadersCompleted == numDescriptors)
            {
                complete();
            }
        }
    }
}